CMAKE_MINIMUM_REQUIRED(VERSION 3.20)
project(RTT307 VERSION 0.1 LANGUAGES C)
SET(CMAKE_SYSTEM_NAME Generic)
SET(CMAKE_SYSTEM_PROCESSOR risc-v)

SET(CMAKE_C_STANDARD 11)
SET(CMAKE_CXX_STANDARD 14)

SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
SET(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
enable_language(ASM)

SET(TOOLCHAIN_PATH "/home/charx/software/MRS_RISCV_Toolchain")
SET(TOOLCHAIN_PREFIX "riscv-none-embed-")
SET(CMAKE_C_COMPILER "${TOOLCHAIN_PATH}/${TOOLCHAIN_PREFIX}gcc")
SET(CMAKE_CXX_COMPILER "${TOOLCHAIN_PATH}/${TOOLCHAIN_PREFIX}g++")
SET(CMAKE_ASM_COMPILER "${TOOLCHAIN_PATH}/${TOOLCHAIN_PREFIX}gcc")
SET(CMAKE_AR "${TOOLCHAIN_PATH}/${TOOLCHAIN_PREFIX}ar")
SET(CMAKE_LINKER "${TOOLCHAIN_PATH}/${TOOLCHAIN_PREFIX}gcc")
SET(CMAKE_SIZE "${TOOLCHAIN_PATH}/${TOOLCHAIN_PREFIX}size")
SET(CMAKE_OBJCOPY "${TOOLCHAIN_PATH}/${TOOLCHAIN_PREFIX}objcopy")
SET(CMAKE_OBJDUMP "${TOOLCHAIN_PATH}/${TOOLCHAIN_PREFIX}objdump")
SET(CMAKE_GDB "${TOOLCHAIN_PATH}/${TOOLCHAIN_PREFIX}gdb")
SET(WLINK_TOOL_EXEC "wlink")


SET(CMAKE_EXPORT_COMPILE_COMMANDS ON)

SET(DEBUG_FLAGS -g)

SET(C_COMPILE_FLAGS "-march=rv32imac -mabi=ilp32 -msmall-data-limit=8 -msave-restore -Os -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -fno-common -Wunused -Wuninitialized ${DEBUG_FLAGS} -std=gnu99")

SET(ASM_COMPILE_FLAGS "-march=rv32imac -mabi=ilp32 -msmall-data-limit=8 -msave-restore -Os -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -fno-common -Wunused -Wuninitialized  ${DEBUG_FLAGS} -x assembler-with-cpp")

SET(LINKER_PATH "${CMAKE_SOURCE_DIR}/Ld/Link.ld")
SET(LD_FLAGS "-march=rv32imac -mabi=ilp32 -msmall-data-limit=8 -msave-restore -Os -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -fno-common -Wunused -Wuninitialized  -T${DEBUG_FLAGS} -nostartfiles -Xlinker --gc-sections -Wl,-Map,${PROJECT_NAME}.map --specs=nano.specs --specs=nosys.specs")

function(append_asm_sources dir variable)
    # 使用GLOB命令查找所有.s文件，不递归
    file(GLOB new_sources1 "${dir}/*.s")
    foreach(ASM_SRC_FILE ${new_sources1})
        set_source_files_properties(${ASM_SRC_FILE} PROPERTIES COMPILE_FLAGS ${ASM_COMPILE_FLAGS})
    endforeach()
    message(STATUS "new1:${new_sources1}")

    # 使用GLOB命令查找所有.S文件，不递归
    file(GLOB new_sources2 "${dir}/*.S")
    foreach(ASM_SRC_FILE ${new_sources2})
        set_source_files_properties(${ASM_SRC_FILE} PROPERTIES COMPILE_FLAGS ${ASM_COMPILE_FLAGS})
    endforeach()
    message(STATUS "new2:${new_sources2}")
    set(${variable} ${${variable}} ${new_sources1} ${new_sources2} PARENT_SCOPE)
endfunction()

function(append_asm_sources_single asm_file variable)
    # 使用GLOB命令查找所有.s文件，不递归
    set_source_files_properties(${asm_file} PROPERTIES COMPILE_FLAGS ${ASM_COMPILE_FLAGS})
    set(${variable} ${${variable}} ${asm_file} PARENT_SCOPE)
endfunction()


function(append_c_sources dir variable)
    # 使用GLOB命令查找所有.C文件，不递归
    file(GLOB new_sources1 "${dir}/*.c")
    foreach(SRC_FILE ${new_sources1})
        set_source_files_properties(${SRC_FILE} PROPERTIES COMPILE_FLAGS ${C_COMPILE_FLAGS})
    endforeach()
    message(STATUS "new1:${new_sources1}")
    message(STATUS "C:${${variable}}")
	
    # 使用GLOB命令查找所有.C文件，不递归
    file(GLOB new_sources2 "${dir}/*.C")
    foreach(SRC_FILE ${new_sources2})
        set_source_files_properties(${SRC_FILE} PROPERTIES COMPILE_FLAGS ${C_COMPILE_FLAGS})
    endforeach()
    message(STATUS "new2:${new_sources2}")
    # 将新找到的源文件追加到指定变量中 PARENT_SCOPE 表示修改父目录的变量
    set(${variable} ${${variable}} ${new_sources1} ${new_sources2} PARENT_SCOPE)
endfunction()


SET(CC_SOURCES "")
SET(ASM_SOURCES "")

include_directories(Debug)
include_directories(Core)
include_directories(User)
include_directories(Peripheral)
include_directories(Peripheral/inc)
include_directories(User/mpu9250/src)
include_directories(User/mpu9250/interface)
include_directories(User/hal)
include_directories(User/cx_lib)
#FreeRTOS
include_directories(FreeRTOS/include)
include_directories(FreeRTOS/portable/GCC/RISC-V)
include_directories(FreeRTOS/portable/GCC/RISC-V/chip_specific_extensions/RV32I_PFIC_no_extensions)
include_directories(FreeRTOS/portable/MemMang)
include_directories(FreeRTOS)

append_c_sources("User" CC_SOURCES)
append_c_sources("Core" CC_SOURCES)
append_c_sources("Peripheral/src" CC_SOURCES)
append_c_sources("User/mpu9250/src" CC_SOURCES)
append_c_sources("User/mpu9250/interface" CC_SOURCES)
append_c_sources("Debug" CC_SOURCES)
append_c_sources("User/hal" CC_SOURCES)
append_c_sources("User/cx_lib" CC_SOURCES)
# FreeRTOS 
append_c_sources("FreeRTOS" CC_SOURCES)
append_c_sources("FreeRTOS/portable/GCC/RISC-V" CC_SOURCES)
append_c_sources("FreeRTOS/portable/MemMang" CC_SOURCES)

message(STATUS "C_SRC:${CC_SOURCES}")

append_asm_sources_single("Startup/startup_ch32v30x_D8C.S" ASM_SOURCES)
append_asm_sources_single("FreeRTOS/portable/GCC/RISC-V/portASM.S" ASM_SOURCES)
message(STATUS "ASM_SRC:${ASM_SOURCES}")


add_executable(${PROJECT_NAME}.elf ${CC_SOURCES} ${ASM_SOURCES})


target_link_options(
    ${PROJECT_NAME}.elf PRIVATE
    "-march=rv32imac"
    "-mabi=ilp32"
    "-msmall-data-limit=8"
    "-msave-restore"
    "-Os"
    "-fmessage-length=0"
    "-fsigned-char"
    "-ffunction-sections"
    "-fdata-sections"
    "-fno-common"
    "-Wunused"
    "-Wuninitialized"
    ""
    "${DEBUG_FLAGS}"
    "-T${LINKER_PATH}"
    "-nostartfiles"
    "-Xlinker"
    "--gc-sections"
    "-Wl,-Map,${PROJECT_NAME}.map"
    "--specs=nano.specs"
    "--specs=nosys.specs"
)

add_custom_command(TARGET ${PROJECT_NAME}.elf POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E echo "Build succeed!Generating hex and bin"
    COMMAND ${CMAKE_OBJCOPY} -Oihex ${PROJECT_NAME}.elf ${PROJECT_NAME}.hex
    COMMAND ${CMAKE_OBJCOPY} -Obinary ${PROJECT_NAME}.elf ${PROJECT_NAME}.bin
    COMMAND ${CMAKE_SIZE} ${PROJECT_NAME}.elf
    COMMAND cp compile_commands.json ${CMAKE_SOURCE_DIR}/compile_commands.json
)

add_custom_target(echo_tool_path
    COMMAND echo ${TOOLCHAIN_PATH})

add_custom_target(disassembly
    COMMAND ${CMAKE_OBJDUMP} -d ${PROJECT_NAME}.elf >> ${PROJECT_NAME}.tmp.asm
    COMMAND cp ${PROJECT_NAME}.tmp.asm ${PROJECT_NAME}.asm
    COMMAND rm ${PROJECT_NAME}.tmp.asm)

find_program(WLINK_EXECUTABLE ${WLINK_TOOL_EXEC})
if(WLINK_EXECUTABLE)
    add_custom_target(flash 
        COMMAND ${WLINK_TOOL_EXEC} flash -a 0x08000000 -e ${PROJECT_NAME}.bin)
    message("wlink found, \"flash\" is avaliable")
else()
    message("wlink not found, \"flash\" is not assesable")
endif()

find_program(DEBUGGER_EXECUTABLE ${CMAKE_GDB})
if(DEBUGGER_EXECUTABLE)
    add_custom_target(debug
        COMMAND ${CMAKE_GDB} -ex "target extended-remote localhost:3333" ${PROJECT_NAME}.elf)
    message("gdb found, \"debug\" is avaliable")
else()
    message("gdb not found, \"gdb\" is not assesable")
endif()


